package com.rent.core.exception;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.rent.common.exception.ApiException;
import com.rent.common.pojo.ResultJSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.common.exceptions.UnauthorizedUserException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;

/**
 * @Author zhang
 * @create 2021/4/15 14:19
 */
@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {


    /***
     * 自定义接口异常
     * @param exception HttpMessageNotReadableException
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ApiException.class)
    public ResultJSON<String> apiExceptionMessage(ApiException exception) {
        //异常信打印出来，定位bug
        log.error("自定义异常:" + exception);
        return ResultJSON.failure(exception.getMessage());
    }

    /***
     * 参数绑定异常
     * @param exception HttpMessageNotReadableException
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResultJSON<String> messageNotReadable(HttpMessageNotReadableException exception) {
        return ResultJSON.failure(exception.getMessage());
    }

    /**
     * 参数不匹配
     *
     * @param exception 异常
     * @return 结果
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public ResultJSON<String> paramsConvertError(IllegalArgumentException exception) {
        InvalidFormatException formatException = (InvalidFormatException) exception.getCause();
        List<JsonMappingException.Reference> e = formatException.getPath();
        String fieldName = "";
        for (JsonMappingException.Reference reference : e) {
            fieldName = reference.getFieldName();
        }
        log.error("参数类型不匹配" + exception);
        return ResultJSON.failure(fieldName + "参数类型不匹配");
    }

    /**
     * 参数校验不通过
     *
     * @param exception 异常
     * @return 结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultJSON<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
        log.error("参数校验不通过" + exception.getMessage());
        BindingResult bindingResult = exception.getBindingResult();
        List<FieldError> list = bindingResult.getFieldErrors();
        if (CollectionUtils.isEmpty(list)) return ResultJSON.failure("参数校验不通过");
        FieldError error = list.get(0);
        String str = error.getField() + ":" + error.getDefaultMessage();
        return ResultJSON.failure("参数校验不通过-" + str);
    }

    /***
     * 无权限访问，如果没有匹配到上述准确的异常，都会到这里来处理
     */
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AccessDeniedException.class)
    public ResultJSON<String> unauthorizedReq() {
        //异常信打印出来，定位bug
        return ResultJSON.noAuth();
    }

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(UnauthorizedUserException.class)
    public ResultJSON<String> unauthorizedVisit() {
        //异常信打印出来，定位bug
        return ResultJSON.noAuth();
    }

    /***
     * 全局异常，如果没有匹配到上述准确的异常，都会到这里来处理
     * @param e 没有匹配到的全局异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(Exception.class)
    public ResultJSON<String> all(Exception e) {
        //异常信打印出来，定位bug
        log.error("全局未找询异常:{}", e.getMessage());
        return ResultJSON.failure("服务器维护中,请稍候再试");
    }


}